package HashMap.Nodo.Operaciones;

import HashMap.Nodo.Nodo;
import HashMap.Nodo.Operacion;
import HashMap.Nodo.TipoBasicoDeDatos;
import HashMap.GenerarCodigoNASM;
import HashMap.Nodo.Categoria;
import HashMap.Nodo.Subclases.Escalar;
import HashMap.Pila;

public class OperacionesLogicas implements Operacion {

    private final Nodo nodo1;
    private final Nodo nodo2;
    private Nodo nodoDefinitivo;

    public OperacionesLogicas(Nodo nodo1) {
        this.nodo1 = nodo1;
        this.nodo2 = nodo1;
    }

    public OperacionesLogicas(Nodo nodo1, Nodo nodo2) {
        this.nodo1 = nodo1;
        this.nodo2 = nodo2;
    }

    @Override
    public int getLongitud() {
        throw new UnsupportedOperationException("Operacion no soportada");
    }

    @Override
    public String generarCodigoNASM() {
        switch (nodo1.getOperacion()) {
            case "OR":
                return generarCodigoNASMdisyuncion();
            case "DOBLEAMPERSON":
                return generarCodigoNASMconjuncion();
            case "ADMIRACION":
                return generarCodigoNASMnegacion();
            default:
                return null;
        }
    }

    @Override
    public Nodo generarNodo(String tokenOperacion) {
        switch (tokenOperacion) {
            case "OR":
                return disyuncion();
            case "DOBLEAMPERSON":
                return conjuncion();
            case "ADMIRACION":
                return negacion();
            default:
                return null;
        }
    }

    private boolean cumpleCondiciones() {
        if (nodo1.getTipoBasicoDeDatos() == TipoBasicoDeDatos.BOOLEAN
                && nodo2.getTipoBasicoDeDatos() == TipoBasicoDeDatos.BOOLEAN
                && (nodo1.getNivelDeIndireccion() == 0 || nodo1.getNivelDeIndireccion() == 1)
                && (nodo2.getNivelDeIndireccion() == 0 || nodo2.getNivelDeIndireccion() == 1)) {
            return true;
        }
        return false;
    }

    private Nodo disyuncion() {
        if (cumpleCondiciones()) {
            nodo1.setOperacion("OR");
            GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
            String nombre = generador.getNombreVariableAuxiliar();
            nodoDefinitivo = new Escalar(nombre, TipoBasicoDeDatos.BOOLEAN, Categoria.VARIABLE, 0, "OR");
            Pila.getInstancia().addNodoALaTablaSuperior(nodoDefinitivo);
            return nodoDefinitivo;
        }
        return null;
    }

    private Nodo conjuncion() {
        if (cumpleCondiciones()) {
            nodo1.setOperacion("DOBLEAMPERSON");
            GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
            String nombre = generador.getNombreVariableAuxiliar();
            nodoDefinitivo = new Escalar(nombre, TipoBasicoDeDatos.BOOLEAN, Categoria.VARIABLE, 0, "DOBLEAMPERSON");
            Pila.getInstancia().addNodoALaTablaSuperior(nodoDefinitivo);
            return nodoDefinitivo;
        }
        return null;
    }

    private Nodo negacion() {
        if (cumpleCondiciones()) {
            nodo1.setOperacion("ADMIRACION");
            GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
            String nombre = generador.getNombreVariableAuxiliar();
            nodoDefinitivo = new Escalar(nombre, TipoBasicoDeDatos.BOOLEAN, Categoria.VARIABLE, 0, "ADMIRACION");
            Pila.getInstancia().addNodoALaTablaSuperior(nodoDefinitivo);
            return nodoDefinitivo;
        }
        return null;
    }

    private String generarCodigoNASMdisyuncion() {
        return "and [" + nodo1.getNombre() + "], [" + nodo2.getNombre() + "]\n"
                + "mov [" + nodoDefinitivo.getNombre() + "], aux";
    }

    private String generarCodigoNASMconjuncion() {
        return "or [" + nodo1.getNombre() + "], [" + nodo2.getNombre() + "]\n"
                + "mov [" + nodoDefinitivo.getNombre() + "], aux";
    }

    private String generarCodigoNASMnegacion() {
        return "not [" + nodo1.getNombre() + "]\n"
                + "mov [" + nodoDefinitivo.getNombre() + "], aux";
    }
}
